<?php
namespace Com\Pay;
class WeixinGzhPay{
    private $config = array();
    public function __construct($send_data){
        $this->config = $send_data;
    }
    /*生成支付连接*/
    public function getUrl($order_info){
        /* 获取提交的订单交易金额 */
        $price = $order_info['paymoney'];
        $notifyUrl = 'http://' . $_SERVER['HTTP_HOST'] . '/Api/NotifyCallback/WeixinGzhNotify';
        $Sumprice = $price * 100;
        $order_sn = $order_info['ordernumber'];
        $post_data = array(
            'appid' =>   $this->config['appid'],
            "mch_id"  => $this->config['mch_id'],
            "nonce_str"  =>  WeixinGzhPay::getNonceStr(),
            'time_start' => date("YmdHis"),
            'time_expire' => date("YmdHis", time() + 600),
            "out_trade_no"  => $order_sn,
            'body' => 'ChangbaoGzh',
            'trade_type' => 'JSAPI',
            'openid' => $order_info['openid'],  // 测试商户不需要填写
            'spbill_create_ip' => get_client_ip(),
            'total_fee' => $Sumprice,
            'notify_url'    => $notifyUrl
        );
        $ContentSign = $this->MakeSign($post_data,$this->config['mch_key']); // 计算出Sign
        $post_data['sign'] = $ContentSign; // Sign签名
        $tar_url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $xml = WeixinGzhPay::ToXml($post_data);
        $res = $this->https_request($tar_url,$xml);
        $res_arr = $this->xmlToArray($res);

        $H5Arr = array(
            'appId' => $res_arr['appid'],
            'timeStamp' => time(),
            'nonceStr' => WeixinGzhPay::getNonceStr(),
            'package' => 'prepay_id=' . $res_arr['prepay_id'],
            'signType' => 'MD5',
        );

        $ContentSign1 = $this->MakeSign($H5Arr,$this->config['mch_key']); // 计算出Sign
        $H5Arr['paySign'] = $ContentSign1;
        if($res_arr['return_code'] == 'SUCCESS'){
            return $H5Arr;
        }
        return '';
    }

    /**
     * 生成签名
     * @return 签名，本函数不覆盖sign成员变量，如要设置签名需要调用SetSign方法赋值
     */
    public function MakeSign($params = array() , $mch_key){
        //签名步骤一：按字典序排序参数
        ksort($params);
        $string = $this->ToUrlParams($params);
        //签名步骤二：在string后加入KEY
        $string = $string . "&key=" . $mch_key;
        //签名步骤三：MD5加密
        $string = md5($string);
        //签名步骤四：所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }

    //回调方法，把返回数据处理成统一规定返回
    public function response(){
        $data  = $this->xmlToArray(file_get_contents('php://input'));
        $MySign = $this->MakeSign($data,$this->config['mch_key']);
        if($data['sign'] == $MySign){
            if($data['result_code'] == 'SUCCESS' && $data['return_code'] == 'SUCCESS' && $this->OrderIsPay($data['transaction_id'] , $data['total_fee'])){ // 返回的状态成功 并且主动查询订单返回的状态成功后才通过
                return true;
            }else{
                // 失败
                return false;
            }
        }else{
            // 失败
            return false;
        }
    }

    /* 订单是否付款 */
    public function OrderIsPay($wxorder = '' , $price){
        $url = 'https://api.mch.weixin.qq.com/pay/orderquery';
        $sendData = array(
            'appid' => $this->config['appid'],
            'mch_id' => $this->config['mch_id'],
            'transaction_id' => $wxorder,
            'nonce_str' => WeixinGzhPay::getNonceStr(),
        );

        $sendData['sign'] = $this->MakeSign($sendData,$this->config['mch_key']);
        $xml = WeixinGzhPay::ToXml($sendData);
        $result = $this->xmlToArray($this->https_request($url , $xml));
        if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS' && $result['total_fee'] == $price){
            return true;
        }
        return false;
    }

    /**
     * 输出xml字符
     * @throws WxPayException
     **/
    public function ToXml($params = array()){
        $xml = "<xml>";
        foreach ($params as $key=>$val)
        {
            if (is_numeric($val)){
                $xml.="<".$key.">".$val."</".$key.">";
            }else{
                $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
            }
        }
        $xml.="</xml>";
        return $xml;
    }

    private function https_request($url, $data = null){
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);

        //参数不为空则为post请求

        if (!empty($data)){

            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($curl);
        curl_close($curl);
        return $output;
    }


    private function gbkToUtf8($arr){
        if(is_array($arr)){
            $res = array();
            foreach($arr as $k => $v){
                $res[$k] = $this->gbkToUtf8($v);
            }
            return $res;
        }else{
            return mb_convert_encoding ( $arr, "UTF-8", "GBK" );
        }
    }

    /**
     *
     * 产生随机字符串，不长于32位
     * @param int $length
     * @return 产生的随机字符串
     */
    public static function getNonceStr($length = 32)
    {
        $str ="";
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        for ( $i = 0; $i < $length; $i++ )  {
            $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
        }
        return $str;
    }


    //将XML转为array
    private function xmlToArray($xml){
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $values;
    }


    public function ToUrlParams($params = array())
    {
        $buff = "";
        foreach ($params as $k => $v)
        {
            if($k != "sign" && $v != "" && !is_array($v)){
                $buff .= $k . "=" . $v . "&";
            }
        }

        $buff = trim($buff, "&");
        return $buff;
    }

}
